﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CLEXA.ClientTools.Collections
{
    public class ObservableDictionary<TKey, TValue> : IObservableDictionary<TKey, TValue>
    {
        private readonly Dictionary<TKey, TValue> dictionary;

        public event ItemChangedHandler<TValue> ItemChanged;
        public event ItemHandler<TValue> ItemRemoved;
        public event ItemHandler<TValue> ItemAdded;

        public TValue this[TKey key]
        {
            get
            {
                lock (dictionary)
                {
                    return dictionary[key];
                }
            }
            set
            {
                lock (dictionary)
                {
                    var oldValue = dictionary[key];
                    dictionary[key] = value;
                    RaiseItemChanged(oldValue, value);
                }
            }
        }

        public IEnumerable<TValue> Values
        {
            get 
            {
                lock (dictionary)
                {
                    return dictionary.Values.ToList();
                }
            }
        }

        public ObservableDictionary(IEnumerable<TValue> collection, Func<TValue, TKey> keySelector)
        {
            this.dictionary = collection.ToDictionary(keySelector);
        }

        public bool ContainsKey(TKey key)
        {
            lock (dictionary)
            {
                return dictionary.ContainsKey(key);
            }
        }

        public bool TryGet(TKey key, out TValue item)
        {
            lock (dictionary)
            {
                return dictionary.TryGetValue(key, out item);
            }
        }

        public void Add(TKey key, TValue item)
        {
            lock (dictionary)
            {
                dictionary.Add(key, item);
            }
            RaiseItemAdded(item);
        }

        public bool Remove(TKey key)
        {
            bool result;
            TValue value;
            lock (dictionary)
            {
                result = dictionary.TryGetValue(key, out value);
                dictionary.Remove(key);
            }
            if (result)
            {
                RaiseItemRemoved(value);
            }
            return result;
        }

        private void RaiseItemChanged(TValue oldValue, TValue newValue)
        {
            var handler = ItemChanged;
            if (handler != null)
            {
                handler.Invoke(this, new ItemChangedEventArgs<TValue>(oldValue, newValue));
            }
        }

        private void RaiseItemRemoved(TValue item)
        {
            var handler = ItemRemoved;
            if (handler != null)
            {
                handler.Invoke(this, new ItemEventArgs<TValue>(item));
            }
        }

        private void RaiseItemAdded(TValue item)
        {
            var handler = ItemAdded;
            if (handler != null)
            {
                handler.Invoke(this, new ItemEventArgs<TValue>(item));
            }
        }
    }
}
